Model class(build model) & train_step

tf.keras.Model 클래스를 상속해서 이용해서 복잡한 모델을 만들 수 있다.
tf.keras.Model 클래스를 상속한 새로운 클래스를 만들고,
생성자 __init__() 메서드를 정의한다.
 __init__ ()에서 self 변수를 통해 참조할 수 있도록 클래스 속성으로 층을 정의하고,
call() 메서드에서 이런 층이 어떻게 정방향 계산에 사용되는지 정의한다.
class MyModel(tf.keras.Model):
def __init__(self):
super(MyModel, self).__init__()
self.hidden_1=tf.keras.layers.Dense(units=4, activation='relu')
self.hidden_2=tf.keras.layers.Dense(units=4, activation='relu')
self.hidden_3=tf.keras.layers.Dense(units=4, activation='relu')
self.output_layer=tf.keras.layers.Dense(units=1, activation='sigmoid')
def call(self, inputs):
h=self.hidden_1(inputs)
h=self.hidden_2(h)
h=self.hidden_3(h)
return self.output_layer(h)
build()
tf.random.set_seed(1)
model=MyModel()
model.build(input_shape=(None, 2))
model.summary()

Model: "my_model"

_________________________________________________________________

Layer (type)                 Output Shape              Param #   

=================================================================

dense_13 (Dense)             multiple                  12        

_________________________________________________________________

dense_14 (Dense)             multiple                  20        

_________________________________________________________________

dense_15 (Dense)             multiple                  20        

_________________________________________________________________

dense_16 (Dense)             multiple                  5         

=================================================================

Total params: 57

Trainable params: 57

Non-trainable params: 0

_________________________________________________________________

compile() & fit()
model.compile(optimizer=tf.keras.optimizers.SGD(), loss=tf.keras.losses.BinaryCrossentropy(),
metrics=[tf.keras.metrics.BinaryAccuracy()])
hist=model.fit(x_train, y_train, validation_data=(x_valid, y_valid), epochs=200, batch_size=2, verbose=0)
텐서플로 2.2부터 tf.keras.Model 클래스를 상속한 경우 train_step() 메서드에서 tf.GradientTape 컨텍스트로
훈련 단계를 세밀하게 조정할 수 있다.
class MyCustomStepModel(MyModel):
def train_step(self, data):
#fit()
x, y=data
#
with tf.GradientTape() as tape:
#
y_pred=self(x)
#compile()
loss=self.compiled_loss(y, y_pred, regularization_losses=self.losses)
#
gradients=tape.gradient(loss, self.trainable_variables)
# )(tf.2.4 )
self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))
#self.optimizeer.minimize(loss, self.trainable_variables, tape=tape)
#compile() metrics
self.compiled_metrics.update_state(y, y_pred)
return {m.name: m.result() for m in self.metrics}
train_step 동작
train_step() 메서드의 data 매개변수를 통해 fit() 메서드로 전달된 훈련 데이터가 튜플로 전달된다.
GradientTpae() 컨텍스트 안의 self(x)를 호출하면 Model 객체의 __call__() 메서드가 시행된다.
(__call__() 메서드가 call() 메서드를 호출함을 포함한다.)

손실을 계산하기 위해서 compiled_loss() 메서드를 이용한다.
compiled_loss 메서드를 통해서 지정한 손실을 자동으로 계산해 준다.
compiled_loss()의 regularization_losses 매개변수에 각 층의 규제 손실을 담은 self.losses를 전달하면,
케라스 층의 kernel_regularizer에서 지정한 규제가 자동으로 손실에 반영된다.

tf.GradientTape.gradient를 통해서 그레이디언트를 계산하고, apply_gradients()로 모델 파라미터를 업데이트 한다.
self.trainable_variables를 사용하여 전체 훈련 가능한 변수를 선택

텐서플로 2.4에서는 옵티마이저 클래스가 리팩토링 되어서 사용자 정의 반복에서
옵티마이저의 minimize() 메서드를 직접 호출 가능하다.
->그레이디언트 계산과 업데이트를 하나의 과정으로 간소화

compile() 메서드에서 지정한 측정 지표를 업데이트 하기 위해서 타깃과 예측 값으로 compiled_metrics.update_state()를 호출한다.

train_step은 최종적으로 측정 지표의 이름과 현재 값을 담은 딕셔너리를 반환한다.